<?php

declare(strict_types=1);
/**
 * This file is part of MoChat.
 * @link     https://mo.chat
 * @document https://mochat.wiki
 * @contact  group@mo.chat
 * @license  https://github.com/mochat-cloud/mochat/blob/master/LICENSE
 */
namespace MoChat\App\WorkEmployee\Logic;

use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Logger\LoggerFactory;
use MoChat\App\Corp\Contract\CorpContract;
use MoChat\App\Corp\Utils\WeWorkFactory;
use MoChat\App\WorkDepartment\Contract\WorkDepartmentContract;
use MoChat\App\WorkEmployee\Constants\AuthStatus;
use MoChat\App\WorkEmployee\Constants\Status;
use MoChat\App\WorkEmployee\Contract\WorkEmployeeContract;
use MoChat\App\WorkEmployee\Queue\SyncEmployeeQueue;

/**
 * Class SyncEmployeeListLogic.
 */
class SyncEmployeeListLogic
{
    /**
     * @Inject
     * @var CorpContract
     */
    protected $corpService;

    /**
     * @var StdoutLoggerInterface
     */
    protected $logger;

    /**
     * @Inject
     * @var WeWorkFactory
     */
    protected $weWorkFactory;

    /**
     * @Inject
     * @var SyncEmployeeQueue
     */
    protected $syncEmployeeQueue;

    /**
     * @Inject
     * @var WorkEmployeeContract
     */
    protected $workEmployeeService;

    /**
     * @Inject
     * @var WorkDepartmentContract
     */
    protected $workDepartmentService;

    public function handle(int $corpId)
    {
        $loggerFactory = make(LoggerFactory::class);
        $this->logger = $loggerFactory->get(__CLASS__);
        $this->logger->debug(sprintf('同步员工ID列表逻辑开始, 企业ID:%s', (string) $corpId));

        $corp = $this->corpService->getCorpById($corpId, ['id', 'auth_type']);

        if ($corp['authType'] == 1) {
            $wxEmployeeIdList = $this->getEmployeeIdList($corpId);
        } else {
            $wxEmployeeIdList = $this->getEmployeeIdListForDepartment($corpId);
        }

        if (empty($wxEmployeeIdList)) {
            return;
        }

        $remoteEmployeeIdList = $wxEmployeeIdList;
        $deleteEmployeeIdList = $this->diffEmployeeIdList($corpId, $remoteEmployeeIdList);

        $this->syncDeleteEmployee($corpId, $deleteEmployeeIdList);
        $this->syncEmployeeDetail($corpId, $wxEmployeeIdList);
    }

    /**
     * 同步删除员工.
     */
    private function syncDeleteEmployee(int $corpId, array $deleteEmployeeIdList)
    {
        if (empty($deleteEmployeeIdList)) {
            return;
        }

        foreach ($deleteEmployeeIdList as $employeeId) {
            $this->workEmployeeService->updateWorkEmployeeById($employeeId, [
                'status' => Status::QUIT, // 标识为已退出
                'auth_status' => AuthStatus::NO,
            ]);
        }
    }

    /**
     * 比较是否有删除的员工.
     */
    private function diffEmployeeIdList(int $corpId, array $remoteEmployeeIdList): array
    {
        $deleteEmployeeIdList = [];

        $localEmployeeList = $this->workEmployeeService->getWorkEmployeesByCorpId($corpId, ['id', 'wx_user_id']);
        if (empty($localEmployeeList)) {
            return $deleteEmployeeIdList;
        }

        foreach ($localEmployeeList as $localEmployee) {
            if (! in_array($localEmployee['wxUserId'], $remoteEmployeeIdList)) {
                $deleteEmployeeIdList[] = $localEmployee['id'];
            }
        }

        return $deleteEmployeeIdList;
    }

    /**
     * 获取员工ID列表.
     *
     * @param int $limit
     * @param mixed $wxEmployeeIdListResult
     */
    private function getEmployeeIdList(int $corpId, string $cursor = '', $limit = 2000, $wxEmployeeIdListResult = []): array
    {
        $weWorkApp = $this->weWorkFactory->getUserApp($corpId);
        $data = [
            'limit' => $limit,
        ];

        if (! empty($cursor)) {
            $data['cursor'] = $cursor;
        }

        $wxResult = $weWorkApp->user->httpPostJson('/cgi-bin/user/list_id', $data);

        if ($wxResult['errcode'] === 48002) {
            return $this->getEmployeeIdListForDepartment($corpId);
        }

        if ($wxResult['errcode'] !== 0) {
            $this->logger->error(sprintf('获取员工列表出错，企业ID:%s，错误信息：%s', (string) $corpId, $wxResult['errmsg']));
            return [];
        }

        $wxEmployeeIdListResult = array_unique(array_merge($wxEmployeeIdListResult, array_column($wxResult['dept_user'], 'userid')));

        if (! empty($wxResult['next_cursor'])) {
            $wxEmployeeIdListResult = $this->getEmployeeIdList($corpId, $wxResult['next_cursor'], 2000, $wxEmployeeIdListResult);
        }

        return $wxEmployeeIdListResult;
    }

    /**
     * 根据部门获取员工ID列表.
     *
     * @param string $cursor
     * @param int $limit
     */
    private function getEmployeeIdListForDepartment(int $corpId): array
    {
        $wxEmployeeIdListResult = [];
        $weWorkApp = $this->weWorkFactory->getUserApp($corpId);

        $departmentList = $this->workDepartmentService->getWorkDepartmentsByCorpId($corpId, ['id', 'wx_department_id']);
        if (empty($departmentList)) {
            return $wxEmployeeIdListResult;
        }

        foreach ($departmentList as $department) {
            $wxResult = $weWorkApp->user->getDepartmentUsers($department['wxDepartmentId']);

            if ($wxResult['errcode'] !== 0) {
                $this->logger->error(sprintf('获取员工列表出错，企业ID:%s，错误信息：%s', (string) $corpId, $wxResult['errmsg']));
                continue;
            }
            $wxEmployeeIdListResult = array_unique(array_merge($wxEmployeeIdListResult, array_column($wxResult['userlist'], 'userid')));
        }

        return $wxEmployeeIdListResult;
    }

    /**
     * 同步员工详情.
     */
    private function syncEmployeeDetail(int $corpId, array $wxEmployeeIdList)
    {
        if (empty($wxEmployeeIdList)) {
            return;
        }

        $wxEmployeeIdList = array_unique($wxEmployeeIdList);
        $employeeCount = count($wxEmployeeIdList);
        $lastEmployee = 0;
        foreach ($wxEmployeeIdList as $key => $wxEmployeeId) {
            if ($employeeCount - 1 === $key) {
                $lastEmployee = 1;
            }
            $this->syncEmployeeQueue->syncEmployeeDetail([
                'corpId' => $corpId,
                'wxEmployeeId' => $wxEmployeeId,
                'lastEmployee' => $lastEmployee,
            ]);
        }
    }
}
